package com.xiaoshuidi.cloud.framework.redis.lock;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 分布式锁
 */
public class DistributeLock implements Lock, AutoCloseable {
    private DistributeLock() {
    }

    private DistributeLock(RLock lock) {
        this.lock = lock;
    }

    private RLock lock;
    private static RedissonClient redissonClient;

    public static void setRedissonClient(RedissonClient redissonClient) {
        DistributeLock.redissonClient = redissonClient;
    }

    public static DistributeLock getLock(String key) {
        return new DistributeLock(redissonClient.getLock(key));
    }

    public static DistributeLock getLock(String... key) {
        RLock[] locks = new RLock[key.length];
        for (int i = 0; i < key.length; i++) {
            locks[i] = redissonClient.getLock(key[i]);
        }
        return new DistributeLock(redissonClient.getMultiLock(locks));
    }

    public static DistributeLock getLock(List<String> keys) {
        RLock[] locks = new RLock[keys.size()];
        for (int i = 0; i < keys.size(); i++) {
            locks[i] = redissonClient.getLock(keys.get(i));
        }
        return new DistributeLock(redissonClient.getMultiLock(locks));
    }

    @Override
    public void close() {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    @Override
    public void lock() {
        this.lock.lock();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        this.lock.lockInterruptibly();
    }

    @Override
    public boolean tryLock() {
        return this.lock.tryLock();
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return this.lock.tryLock(time, unit);
    }

    @Override
    public void unlock() {
        close();
    }

    @Override
    public Condition newCondition() {
        return this.lock.newCondition();
    }

    public RLock getRLock() {
        return this.lock;
    }
}
